/**
******************************************************************************
  * @file           : studio_tcp.h
  * @author         : wangyingjie
  * @brief          : socket tcp client 类封装 基于 boost::asio
  * @attention      : None
  * @date           : 2025/7/1
******************************************************************************
  */

#ifndef STUDIO_TCP_CLIENT_HPP
#define STUDIO_TCP_CLIENT_HPP

#include "studio_macros.h"

#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/system/error_code.hpp>

// 重连时间 单位 秒
const int RECONNECT_INTERVAL = 3;

namespace asio = boost::asio;
using tcp = asio::ip::tcp;

class studio_tcp_client
{
public:
    using message_handler = std::function<void(const std::string&)>;

    /// tcp client 初始化
    /// @param host 服务端IP
    /// @param port 服务端端口
    /// @param buffer_size 读取字节缓冲区大小 默认 4096 个字节 4KB
    studio_tcp_client(const std::string& host,
                      const std::string& port,
                      size_t buffer_size = 4096) // 默认4KB
        : io_(),
          socket_(io_),
          host_(host),
          port_(port),
          reconnect_timer_(io_),
          buffer_(buffer_size),
          // 初始化缓冲区
          connected_(false)
    {
    }

    ~studio_tcp_client()
    {
        stop();
    }

    /// 设置接收消息的回调函数
    /// @param handler 回调函数句柄 直接传入函数
    void set_message_handler(message_handler handler)
    {
        msg_handler_ = handler;
    }

    /// 启动客户端
    void start()
    {
        connect();
        worker_thread_ = std::make_unique<std::thread>([this]() {
            io_.run();
        });
    }

    /// 停止客户端
    void stop();


    /// 发送消息给服务端
    /// @param message 消息内容
    /// @return
    bool send(const std::string& message);

private:
    /// 链接服务端
    void connect();

    /// 重连函数
    void on_connect(const boost::system::error_code& ec, const tcp::endpoint&);

    /// 读取数据
    void do_read();

    /// 读取数据的回调函数
    void on_read(const boost::system::error_code& ec, std::size_t bytes_transferred);

    /// 写入数据
    void start_write();

    void on_write(const boost::system::error_code& ec, std::size_t /*bytes_transferred*/)
    {
        write_in_progress_.store(false);
        // 如果队列中还有消息，继续发送
        start_write();
    }

    /// 重连定时器的回调函数
    void on_reconnect_timer(const boost::system::error_code& ec)
    {
        if (!ec)
        {
            connect();
        }
    }

    /// 断开连接并重新连接
    void disconnect_and_reconnect(std::chrono::steady_clock::duration delay);

private:
    asio::io_context io_;
    tcp::socket socket_;
    std::string host_;
    std::string port_;

    std::vector<char> buffer_;

    std::unique_ptr<std::thread> worker_thread_;
    message_handler msg_handler_;

    std::queue<std::string> write_queue_;
    std::mutex write_mutex_;

    asio::steady_timer reconnect_timer_;
    std::atomic<bool> connected_;
    std::atomic<bool> stopped_{false};
    std::atomic<bool> write_in_progress_{false};
};

#endif // STUDIO_TCP_CLIENT_HPP